package model

import (
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
)

type UserStatus int

const (
	Active UserStatus = iota
	InActive
	Removed
)

type User struct {
	ID, // Used for key.
	Name,
	Email string
	Created,
	LastUpdated time.Time
	Status UserStatus
}

var (
	UserAlreadyRegisteredErr = fmt.Errorf("User is already registered")
	UserNotRegisteredErr     = fmt.Errorf("User is not registered")
)

type UserModel interface {
	CreateUser(user *User) (*User, error)
	DeleteUser(user *User) error
	UpdateUser(user *User) error
	GetUser(id string) (*User, error)
}

const kind = "User"

// TODO: split this implementation.
type userModelAppEngine struct {
	c appengine.Context
}

func NewUserModelAppEngine(c appengine.Context) UserModel {
	var umi UserModel = userModelAppEngine{
		c: c,
	}
	return umi
}

func (um userModelAppEngine) CreateUser(user *User) (*User, error) {
	_, err := um.GetUser(user.ID)
	if err == nil {
		return nil, UserAlreadyRegisteredErr
	}
	if err != UserNotRegisteredErr {
		return nil, err
	}
	user.Created = time.Now()
	user.LastUpdated = time.Now()
	user.Status = InActive
	_, err = datastore.Put(um.c, um.key(user.ID), user)
	if err != nil {
		return nil, err
	}
	return user, nil
}

func (um userModelAppEngine) DeleteUser(user *User) error {
	_, err := um.GetUser(user.ID)
	if err != nil {
		return err
	}
	err = datastore.Delete(um.c, um.key(user.ID))
	return err
}

func (um userModelAppEngine) UpdateUser(user *User) error {
	_, err := um.GetUser(user.ID)
	if err != nil {
		return err
	}
	user.LastUpdated = time.Now()
	_, err = datastore.Put(um.c, um.key(user.ID), user)
	return err
}

func (um userModelAppEngine) GetUser(id string) (*User, error) {
	var user *User
	err := datastore.Get(um.c, um.key(id), user)
	if err != nil {
		// Do proper action on each different err.
		return nil, UserNotRegisteredErr
	}
	return user, nil
}

func (um userModelAppEngine) key(id string) *datastore.Key {
	return datastore.NewKey(um.c, kind, id, 0, nil)
}
